home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 11 / develop 11 code / MultiBuffer / MultiBuffer Source / PlayFromFile.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-15  |  8.8 KB  |  293 lines  |  [TEXT/MPS ]

  1. /*
  2. 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
  3. |         |         |         |         |         |         |         |         |         |         
  4.  
  5. */
  6.  
  7. /*
  8. **        PlayFromFile
  9. **
  10. **            This module contains the routines that impliment the play from file options.
  11. **
  12. **            (NMD)    9//91        created
  13. **            (NMD)    10/14/91    ReadProc - moved all reads out of the code into this routine:
  14. **                                    facilitates putting other types of reads in (ex. ADSP instead
  15. **                                    of File System based)
  16. **            (NMD)    10/15/91    ProcessingProc    - Added twos to offset conversion.
  17. **            (NMD)    11/10/91    BackReadProc - implimented the "Play Backwards" routines.
  18. */
  19.  
  20.  
  21. #pragma load "MacHeaders"
  22.  
  23.  
  24. #ifndef __MAININCLUDES__
  25. #include "MainApp.h"
  26. #endif
  27.  
  28. #ifndef    __DOUBLEBUFFERINCLUDES__
  29. #include "DoubleBuffer.h"
  30. #endif
  31.  
  32. extern SndChannelPtr    gSndChan;
  33.  
  34. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  35. // High Level routine for playing a file
  36. OSErr PlayFile(Boolean foreward, Ptr *privateData)
  37. {
  38.     OSErr                    err                            = noErr;
  39.     SFTypeList                fTypes;
  40.     StandardFileReply        sReply;
  41.     short                    fRefNum;
  42.     unsigned long            playLength                    = 0;
  43.     long                    dataOffset                    = 0;
  44.     SoundHeader                tempHeader;
  45.     
  46.     
  47.     // We're only interested in AIFF files showing up in the standard file dialog; set
  48.     //    the type list accordingly.
  49.     fTypes[0] = AIFFID;
  50.     
  51.     StandardGetFile (NULL, 1, fTypes, &sReply);
  52.     if (sReply.sfGood) {
  53.     
  54.         err = FSpOpenDF (&sReply.sfFile, fsRdPerm, &fRefNum);
  55.         if (err == noErr) {
  56.  
  57.             playLength = GetAIFFHeaderInfo(fRefNum, &tempHeader);    // Get Header & sound len
  58.             err = GetFPos (fRefNum,&dataOffset);
  59.             
  60.             if (playLength != 0) {
  61.                 if (foreward)
  62.                     err = DoubleBuffer(gSndChan, fRefNum, (ProcPtr)ReadProc, (ProcPtr)ProcessingProc,
  63.                                             &tempHeader, playLength, dataOffset, privateData);
  64.                 else
  65.                     err = DoubleBuffer(gSndChan, fRefNum, (ProcPtr)BackReadProc, 
  66.                                             (ProcPtr)BackProcessingProc,&tempHeader, playLength, dataOffset, privateData);
  67.             }                
  68.         }
  69.     }
  70.     return (err);
  71. }
  72.  
  73. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  74. //  Pre-fills each of the buffers
  75. OSErr PrimeBuffers (PrivateDBInfoPtr dbInfo, SoundHeaderPtr generalHeader)
  76. {
  77.     OSErr                    err                            = noErr;            // error bucket
  78.     long                    actualBytes                    = kBufferSize;        // bytes (to) read
  79.     short                    index                         = 0;                // index for buffer elements
  80.     short                    headerOffset                = 0;    
  81.  
  82.     headerOffset = sizeof(dbInfo->buffers[index].header->samplePtr) +        // don't step on full header 
  83.                             sizeof(dbInfo->buffers[index].header->length);
  84.  
  85.     for (index = 0; index < kNumBuffers; index++) {
  86.         DebugMessage ("\pabout fill header's buffer");
  87.  
  88.         //    Make a copy of the header
  89.         BlockMove ((Ptr)generalHeader+headerOffset, (Ptr)dbInfo->buffers[index].header+headerOffset,
  90.                     sizeof (SoundHeader)-headerOffset);
  91.         
  92.         err = (*(dbInfo->readProcPtr)) (dbInfo, index, false);                // fill the buffer...
  93.  
  94.         switch (err) {
  95.             case noErr:                                                        // Happy - movin' on
  96.                 if (dbInfo->processingProcPtr)
  97.                     CallDTWithParam (dbInfo->processingProcPtr,
  98.                                      &(dbInfo->buffers[index]));
  99.                 break;
  100.                 
  101.             case eofErr:                                                    // EEK: ran out of file!
  102.                 Assert (true, "\pHit EOF trying to fill thisHeader");
  103.                 if (dbInfo->processingProcPtr)
  104.                     CallDTWithParam (dbInfo->processingProcPtr, &(dbInfo->buffers[index]));
  105.                 dbInfo->bytesToGo = 0;                                        //   we be out 'o data
  106.                 err = noErr;                                                //   not really an error
  107.                 break;                                                        //   don't *need* this
  108.                 
  109.             default:                                                        // EEK: got a BAD error!
  110.                 Assert (true, "\pGot a really bad error trying to fill a header");
  111.         }
  112.     }
  113.     return (err);                                                            // Happy: bye-bye
  114. }
  115.  
  116. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  117. // read procedure for retrieving sound data from the file
  118. OSErr ReadProc (void *private, short bufNum, Boolean asynch)
  119. {
  120.     OSErr                             err                         = noErr;
  121.     long                            oldA5                        = nil;
  122.     long                            rdSize                        = 0;
  123.     register strippedDownReadPBPtr    pb                            = nil;
  124.     PrivateDBInfoPtr                dbInfo;
  125.  
  126.     dbInfo = (PrivateDBInfoPtr) private;
  127.  
  128.     if (dbInfo->bytesToGo == 0)                                                // No Bytes to read? bail
  129.         err = eofErr;
  130.     else {
  131.  
  132.         //    Again, optimizing out some of these de-references
  133.         pb = &(dbInfo->buffers[bufNum].readPB.pb);
  134.     
  135.         if (dbInfo->bytesToGo > kBufferSize)
  136.             rdSize = kBufferSize;
  137.         else
  138.             rdSize = dbInfo->bytesToGo;
  139.     
  140.         pb->ioFRefNum = dbInfo->refNum;                                        // set up the paramBlock
  141.         pb->ioBuffer = dbInfo->buffers[bufNum].header->samplePtr;
  142.         pb->ioReqCount = rdSize;
  143.         pb->ioPosMode = fsAtMark;
  144.         pb->ioPosOffset =0;
  145.         dbInfo->buffers[bufNum].readPB.userInfo = (Ptr)dbInfo;
  146.         dbInfo->buffers[bufNum].readPB.headerNum = bufNum;
  147.     
  148.         if (asynch)
  149.             pb->ioCompletion = (ProcPtr)&CompleteRead;
  150.         else
  151.             pb->ioCompletion = nil;
  152.     
  153.         err = PBRead ((ParmBlkPtr)pb, asynch);
  154.         Assert (err, "\p(ReadProc) croaked queueing read ;g");
  155.     
  156.         dbInfo->bytesToGo -= rdSize;
  157.     
  158.         if (!asynch) {
  159.             dbInfo->buffers[bufNum].header->length = pb->ioActCount;
  160.     
  161.             //    if we were called synchronously, chances are we care about the when we hit the
  162.             //     "End of File", so if rdSize is less than the buffersize we know this was the
  163.             //     last buffer read...
  164.             if (rdSize < kBufferSize)
  165.                 err = eofErr;
  166.         }
  167.     }
  168.     return (err);
  169. }
  170.  
  171. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  172. void ProcessingProc (void)
  173. {
  174.     SampleBufferPtr bufPtr;
  175.  
  176.     bufPtr = getDTParam();                                                    // retrieve sample info
  177.  
  178.     TwosToOffset (bufPtr->header->samplePtr, bufPtr->header->length);
  179.  
  180.     bufPtr->flags = kBufferReady;
  181. }
  182.  
  183. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  184. // read procedure used for playing a file backwards.  Starts reading from the
  185. // end of file and moves toward the beginning of file.
  186. OSErr BackReadProc (void *private, short bufNum, Boolean asynch)
  187. {
  188.     OSErr                             err                         = noErr;
  189.     long                            oldA5                        = nil;
  190.     long                            rdSize                        = 0;
  191.     register strippedDownReadPBPtr    pb                            = nil;
  192.     PrivateDBInfoPtr                dbInfo;
  193.  
  194.     dbInfo = (PrivateDBInfoPtr) private;
  195.  
  196.     if (dbInfo->bytesToGo == 0)                                                // No Bytes to read? bail
  197.         err = eofErr;
  198.         else {
  199.         
  200.         //    Again, optimizing out some of these de-references
  201.         pb = &(dbInfo->buffers[bufNum].readPB.pb);
  202.     
  203.         if (dbInfo->bytesToGo > kBufferSize)
  204.             rdSize = kBufferSize;
  205.         else
  206.             rdSize = dbInfo->bytesToGo;
  207.     
  208.         pb->ioFRefNum = dbInfo->refNum;                                        // set up the paramBlock
  209.         pb->ioBuffer = dbInfo->buffers[bufNum].header->samplePtr;
  210.         pb->ioReqCount = rdSize;
  211.         pb->ioPosMode = fsFromStart;
  212.         pb->ioPosOffset =dbInfo->fileDataStart + dbInfo->bytesToGo - rdSize;
  213.         dbInfo->buffers[bufNum].readPB.userInfo = (Ptr)dbInfo;
  214.         dbInfo->buffers[bufNum].readPB.headerNum = bufNum;
  215.     
  216.         if (asynch == true)
  217.             pb->ioCompletion = (ProcPtr)&CompleteRead;
  218.         else
  219.             pb->ioCompletion = nil;
  220.     
  221.         err = PBRead ((ParmBlkPtr)pb, asynch);
  222.         Assert ((err != noErr), "\p(ReadProc) croaked queueing read ;g");
  223.     
  224.         dbInfo->bytesToGo -= rdSize;
  225.     
  226.         if (!asynch) {
  227.             dbInfo->buffers[bufNum].header->length = pb->ioActCount;
  228.     
  229.             //    if we were called synchronously, chances are we care about the when we hit the
  230.             //     "End of File", so if rdSize is less than the buffersize we know this was the
  231.             //     last buffer read...
  232.             if (rdSize < kBufferSize)
  233.                 err = eofErr;
  234.         }
  235.     }
  236.     return (err);
  237. }
  238.  
  239. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  240. // processing procedure used when playing a file backwards
  241. void BackProcessingProc (void)
  242. {
  243.     SampleBufferPtr bufPtr;
  244.  
  245.     bufPtr = getDTParam();                                                    // retrieve sample info
  246.  
  247.     Reverse     (bufPtr->header->samplePtr, bufPtr->header->length);
  248.  
  249.     bufPtr->flags = kBufferReady;
  250. }
  251.  
  252. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  253. // convert the buffer from "twos complimentary" into "offset binary"
  254.  
  255. void TwosToOffset (Ptr buffer,long length)
  256. {
  257.     short            i;
  258.     
  259.     // divide the length by four (by shifting right) to find the number of long words
  260.     for (i = (length >> 2) - 1; i >= 0; --i)
  261.         * ((long *)buffer)++ ^= 0x80808080;
  262.     
  263.     // do the remaining number of bytes (by ANDing to get the two least significant bits)
  264.     for (i = (length & 3) - 1; i >= 0; --i)
  265.         * (char *)buffer++ ^= 0x80;
  266.  
  267. }
  268.  
  269. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  270. // reverse all the bytes in the buffer, and convert them to offset-binary
  271. void Reverse (char *buffer, long length)
  272. {
  273.     short            i;
  274.     unsigned char    *endBuffer;
  275.     unsigned char    *startBuffer = buffer;
  276.     unsigned char    saveByte;
  277.     unsigned char    mask = 0x80;
  278.     
  279.     endBuffer = (buffer + length);
  280.     for (i = (length >> 1) - 1; i >= 0; --i) {
  281.         saveByte = *--endBuffer;
  282.         *endBuffer = *startBuffer;
  283.         *startBuffer = saveByte;
  284.         *endBuffer ^= mask;
  285.         *startBuffer++ ^= mask;
  286.     }
  287.     
  288.     // if there is an exact mid-point then the length is odd
  289.     // at this stage the pointer will be at the middle byte
  290.     if (length & 1)
  291.         *startBuffer ^= mask;
  292. }
  293.